import UIKit
//存储属性。属性将值跟特定的类。结构。或者枚举管理。存储属性存储常量或变量作为实例的一部分。计算属性计算一个值，计算属性可以用于类，结构体和枚举，存储属性只能用于类和结构体。类型属性是一种属于类型本身的属性。另外，可以定义属性观察器来监控属性值的变化，由此来触发一个自定义的操作。属性观察器可以添加到自己写的存储属性上，也可以添加到从父类继承的属性上。

//存储属性。存储属性是存储在特定类型或结构体的实例里面的一个常量或变量，存储属性可以是变量存储属性，也可以是常量存储属性。
struct FixedLengthRange {
    var firstValue:Int
    let length: Int
}

var rangOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
rangOfThreeItems.firstValue = 6

//如果创建了一个结构体的实例并赋值给常量。则无法修复实例的任何属性。即使定义了变量存储属性
let rangOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
//rangOfFourItems.firstValue = 6

//延迟存储属性 当第一次被调用的时候才会计算其初始值的属性。在属性声明前加lazy来表示延迟存储属性,注意，必须将延迟存储属性声明成变量var。
class DataImporter {
    var fileName = "data.txt"
}
class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
}
let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
manager.importer.fileName = "1.txt" //使用了lazy的importer此时才会被创建
//存储属性和实例变量 Swift中的属性没有对应的实例变量。
//计算属性 提供一个getter来获取值。一个可选的setter来间接设置其他属性或变量的值。
struct Point {
    var x = 0.0, y = 0.0
}

struct Size {
    var width = 0.0, height = 0.0
}

struct Rect {
    var origin = Point()
    var size = Size()
    var center:Point {
        get {
            let centerX = origin.x + (size.width) / 2
            let centerY = origin.y + (size.height) / 2
            return Point(x: centerX, y: centerY)
        }
        
        set(value) {
            origin.x = value.x - (size.width) / 2
            origin.y = value.y - (size.height) / 2
        }
    }
}

var sqare = Rect(origin: Point(x:0.0,y: 0.0), size: Size(width: 10.0, height: 10.0))
let initalSquareCenter = sqare.center
sqare.center = Point(x: 15.0, y: 15.0)
print("square.orign is now at \(sqare.origin.x), \(sqare.origin.y)")

//便捷setter声明
struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + size.width / 2
            let centerY = origin.y + size.height / 2
            return Point(x: centerX, y:centerY)
        }
        set {
            origin.x = newValue.x - size.width / 2
            origin.y = newValue.y - size.height / 2
        }
    }
}

//只读计算属性 只有getter没有setter的计算属性
struct Cuboid {
    var width = 0.0,height = 0.0, depth = 0.0
    var colume : Double {
        return width * height * depth
    }
}

//属性观察器 willset didset 注意，willset和didset不会在属性初始化过程中被调用，他们只会在属性的值在初始化之外被调用

class StepCounter {
    var totalSteps:Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totolsteps to \(newTotalSteps)")
        }
        
        didSet {
            if totalSteps > oldValue {
                print("Added \(totalSteps - oldValue) steps.")
            }
        }
    }
}


let counter = StepCounter()
counter.totalSteps = 200
counter.totalSteps = 360
counter.totalSteps = 896

//全局变量和局部变量。全局变量是在函数，方法，闭包或任何类型之外定义的变量。局部变量是在函数，方法或闭包内部定义的变量
//类型属性 类型本身定义的属性，跟实例无关。使用static定义值类型的类型属性，使用class定义类的类型属性。
struct SomeStruct {
    static var storedTypeProperty = "some value"
    static var computedTypeProperty: Int {
        return 100
    }
}

SomeStruct.storedTypeProperty
SomeStruct.computedTypeProperty


enum SomeEnumration {
  static var storedTypeProperty = "some value"
    static var computedTypeProperty : Int {
        return 100
    }
}

SomeEnumration.storedTypeProperty
SomeEnumration.computedTypeProperty


class SomeClass {
    class var computedTypeProperty:Int {
        return 100
    }
}

SomeClass.computedTypeProperty

struct AudioChannel {
    static let thresholLevel = 10
    static var maxInputLevelForAllChannels = 0
    var currentLevel: Int {
        didSet {
            if currentLevel > AudioChannel.thresholLevel{
                currentLevel = AudioChannel.thresholLevel
            }
            
            if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                AudioChannel.maxInputLevelForAllChannels = currentLevel
            }
        }
    }
}

var leftChannel = AudioChannel(currentLevel: 0)
leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
print(AudioChannel.maxInputLevelForAllChannels)


var rightChannel = AudioChannel(currentLevel: 0)
rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
print(AudioChannel.maxInputLevelForAllChannels)
